#include "thread.h"

#include <utility>
#include "log.h"
#include "util.h"

namespace yuechuan {
    static thread_local Thread *t_thread = nullptr;             /// 线程局部变量，用于表示当前线程
    static thread_local std::string t_thread_name = "UNKNOW";
    static yuechuan::Logger::ptr g_logger = YUECHUAN_LOG_NAME("system");



    Thread *Thread::GetThis() {
        return t_thread;
    }

    const std::string &Thread::GetName() {
        return t_thread_name;
    }

    void *Thread::run(void *arg) {
        Thread *thread = (Thread *) arg;
        t_thread = thread;
        t_thread_name = thread->m_name;
        thread->m_id = yuechuan::GetThreadId();
        pthread_setname_np(pthread_self(), thread->m_name.substr(0, 15).c_str());
        std::function<void()> cb;
        cb.swap(thread->m_callback);    /// 防止在回调函数中有智能指针在引用时不会被释放掉，如果仅仅是复制的话，其中的智能指针的引用就会加一
        thread->m_semaphore.notify();

        cb();
        return nullptr;
    }

    void Thread::setName(const std::string &name) {
        if (t_thread) {
            t_thread->m_name = name;
        }
        t_thread_name = name;
    }

    Thread::Thread(std::function<void()> callback, const std::string name)
            : m_callback(std::move(callback)), m_name(name) {
        int rt = pthread_create(&m_thread, nullptr, &Thread::run, this);
        if (rt) {
            YUECHUAN_LOG_ERROR(g_logger) << "pthread_create thread fail, rt=" << rt << " name=" << name;
            throw std::logic_error("pthread_create error");
        }
        m_semaphore.wait();         /// 解决线程执行顺序问题，可能当前线程创建时前面的线程还在运行，导致该线程不能运行
                                    /// 我们要实现的是当前线程创建就要进入运行状态
                                    /// 所以在创建线程完成后执行信号量的 wait函数，在回调函数中执行信号量的notify唤醒操作
    }

    Thread::~Thread() {
        // YUECHUAN_LOG_INFO(g_logger) << "Thread::~Thread " << getId();
        if (m_thread) {
            pthread_detach(m_thread);
        }

    }

    void Thread::join() {
        if (m_thread) {
            int rt = pthread_join(m_thread, nullptr);
            if (rt) {
                YUECHUAN_LOG_ERROR(g_logger) << "pthread_join thread fail, rt=" << rt;
                throw std::logic_error("pthread_join error");
            }
            m_thread = 0;
        }
    }

} // namespace yuechuan
